package com.atguigu.juc.atomics;

import java.util.concurrent.CountDownLatch;
import java.util.concurrent.atomic.AtomicIntegerFieldUpdater;

/**
 * @author yanglin
 * @create 2024-01-26 15:58 星期五
 * description:
 */
public class AtomicIntegerFieldUpdateDemo {

    /**
     * 以一种线程安全的方式操作非线程安全对象的某些字段
     * 
     * 需求：
     *  10个线程
     *  每个线程转账1000
     *  不使用synchronized，使用AtomicIntegerFieldUpdater来实现
     */

    public static void main(String[] args) throws InterruptedException {
        BankAccount bankAccount = new BankAccount();
        CountDownLatch countDownLatch = new CountDownLatch(10);
        for (int i = 0; i < 10; i++) {
            new Thread(() -> {
                try {
                    for (int j = 0; j < 1000; j++) {
                        bankAccount.transMoney(bankAccount);
                    }
                }finally {
                    countDownLatch.countDown();
                }
            }).start();
        }
        
        countDownLatch.await();
        int result = bankAccount.getMoney();
        System.out.println(result);
    }
    
    
}

//资源类
class BankAccount {
    String bankName = "ICBC";
    
    //1、更新对象的属性必须使用public volatile修饰符
    public volatile int money = 0;  //钱数
    
//    public void add(){
//        money++;
//    }

    //2、因为对象的属性修改类型原子类都是抽象类，所以每次使用必须使用静态方法newUpdater()创建一个更新器，
    // 并且需要设置想要更新的类和属性
    AtomicIntegerFieldUpdater<BankAccount> fieldUpdater = AtomicIntegerFieldUpdater.newUpdater(BankAccount.class,"money");
    
    //不加synchronized，保证高性能原子性
    public void transMoney(BankAccount bankAccount){
        fieldUpdater.getAndIncrement(bankAccount);
    }
    

    public String getBankName() {
        return bankName;
    }

    public void setBankName(String bankName) {
        this.bankName = bankName;
    }

    public int getMoney() {
        return money;
    }

    public void setMoney(int money) {
        this.money = money;
    }

    @Override
    public String toString() {
        return "BankAccount{" +
                "bankName='" + bankName + '\'' +
                ", money=" + money +
                '}';
    }
}
